import { callAPI } from './callApi';
import { ICallService, IAsyncService } from './callService';
import { IAsyncState } from './IAsyncState';

type callFn = typeof callAPI | ICallService;

// function example() {
//   asCall(as, "get /oss/v1.0/nc/ncInfos", {
//     orgCode,
//     param1,
//     param2,
//   }]).then(asNext => {...});
// }

export function createAsCall(callApi:callFn = callAPI, responseStandardize: Function) {

  /**
   * 以状态跟踪模式调用 API
   * @param as 异步跟踪状态变量
   * @param servicPath 调用服务路径
   * @param request 调用服务请求参数
   */
  function asCall(as: IAsyncState, servicPath: string | IAsyncService, request: any) {
    let asStart: typeof as;

    const debugName = (servicPath instanceof Function) ? servicPath.name : servicPath;

    function markStart() {
      as.ss(ts => {
        asStart = {
          ...ts,
          s: ts.s + 1,
          o: false,
          e: false,
          p: true,
          b: new Date(),
          f: undefined,
          u: debugName,
          r: request,
          d: undefined,
          E: undefined,
          rsp: null,
        } as IAsyncState;
        return asStart;
      });
    }
    // setTimeout(markStart, 0); // 必须放到异步中，而非 render 同步执行中
    // new Promise(() => markStart);
    Promise.resolve().then(markStart); // 可以在尽快执行 markStart 的基础上，确保 as.ss 完成执行
    // markStart(); // 警告：在 dev-tools 中查看包含的组件，as.ss 就不会执行；

    return new Promise<IAsyncState>((resolve, reject) => {
      const promise = callApi(servicPath, request);
      let asNext: IAsyncState; // .then.catch 到的必须是最新的 as 值
      promise.then((resp: any) => {
        const std = responseStandardize(resp);
        let overrided = false; // 是否被后面调用覆盖了
        as.ss(ts => {
          if (!asStart) alert('no asStart!'); // 为了方便发现和报告异常，用于完善本软件
          if (asStart && ts.s > asStart.s) {
            // 还没返回，后面又有调用了，应该 cancel 掉后续处理
            overrided = true;
            console.log('promise cancelled');
            return ts; // cancel 掉了，as 不改变了
          }
          asNext = {
            ...ts,
            rsp: resp,
            p: false,
            f: new Date(),
            ...std,
          };
          return asNext;
        });
        if (overrided) {
          as.ss(ts => {
            asNext = {
              ...ts,
              p: false,
              f: new Date(),
              o: false,
              e: true,
              E: {
                canceled: true,
              },
            };
            return asNext;
          });
          reject(asNext);
          return;
        }
        // 根据收到的响应动态判断算成功算失败，通常服务端返回200，但是业务上可以是成功或者失败
        if (std.e) {
          reject(asNext);
        } else {
          resolve(asNext);
        }
      });
      promise.catch((error: any) => {
        as.ss(ts => {
          asNext = {
            ...ts,
            p: false,
            f: new Date(),
            o: false,
            e: true,
            E: error,
          };
          return asNext;
        });
        reject(asNext);
      });
    })

  }
  return asCall;
}
